package com.kitty.game.rank.service.handler;

import com.kitty.game.rank.model.record.RankRecord;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
@Slf4j
public abstract class RankHandler {

	/**
	 * 用于快速查找 id --> record
	 */
	private ConcurrentMap<Serializable, RankRecord> cache = new ConcurrentHashMap<>();

	private ConcurrentSkipListMap<RankRecord, Serializable> ranks = new ConcurrentSkipListMap<>();

	@Getter
	@Setter
	private int rankSize = 100;
	/**
	 * 缓存数量要比排行榜数量大，防止战力下降，没有数据补充
	 */
	@Getter
	private int cacheSize = rankSize + 50;

	/**
	 * 读取数据库进行初始化
	 */
	protected abstract void  init();

	protected void put(Serializable key, RankRecord data) {
		cache.put(key, data);
		ranks.put(data, key);
		if (ranks.size() > cacheSize) {
			Map.Entry<RankRecord, Serializable> lastEntry = ranks.pollLastEntry();
			remove(lastEntry.getValue());
		}


		//log.info("cache.size:{}, ranks.size:{}", cache.size(), ranks.size());
	}

	protected void remove(Serializable key) {
		RankRecord value = cache.remove(key);
		if (value != null) {
			ranks.remove(value);
		}
	}

	/**
	 * 由外部接受事件进行数据更新
	 * @param key
	 * @param data
	 */
	public void update(Serializable key, RankRecord data) {
//		Logger logger = LoggerFactory.getLogger(getClass());
//		logger.warn("key:{}, data:{}", key, JsonUtils.object2String(data));
		remove(key);
		put(key, data);
	}

	public List<RankRecord> getRecordsFrom(int start, int end) {
		List<RankRecord> result = new ArrayList<>();

		int i =0;
		for (Iterator<Map.Entry<RankRecord, Serializable>> it= ranks.entrySet().iterator(); it.hasNext();) {
			Map.Entry<RankRecord, Serializable> next = it.next();
			if (i++ < end) {
				result.add(next.getKey());
			}
		}

		return result;
	}

	public List<RankRecord> getRecordsFrom() {
		return getRecordsFrom(0, getRankSize());
	}

}
